if not __RUNTIME_LUA__ then
    __RUNTIME_LUA__ = true
    local __version__ = "1.5.7"

    Include("Emulator.lua")
    Include("Context.lua")
    Include("Routine.lua")
    Include("Exception.lua")
    Include("JSON.lua")
    Include("Version.lua")
    Version:set("Runtime", __version__)
    Version:require("Runtime", "Routine", "1.5.6")

    ---@class Runtime 运行时库
    ---@field private routines Routine[] 例程列表。
    ---@field private routine_mode integer 例程执行模式。
    ---@field private ROUTINE_BURST_MODE integer 猝发例程模式。
    ---@field private ROUTINE_SEQUENCE_MODE integer 顺序例程模式。
    ---@field private ROUTINE_RANDOM_MODE integer 随机例程模式。
    ---@field private routine_mask_flag boolean 例程屏蔽标志位。`true` 屏蔽例程，`false` 允许受理例程。
    ---@field private routine_busy_flag boolean 例程忙标志，用于避免例程嵌套。`true` 表示当前正在受理其他例程，`false` 表示空闲。
    ---@field private routine_mask_flag_stack boolean[] 存放例程屏蔽标志位的栈。
    ---@field private routine_context Context[] 例程发生时保存的例程现场。
    ---@field private expected_sleep_time number 根据最近睡眠情况推测的一轮睡眠时间。
    ---@field private actual_sleep_time number 最近一次实际的一轮睡眠时间。
    ---@field private last_routine_id integer 最近一次处理的例程对应标识符。
    ---@field private last_exception Exception 最近一次发生的异常。
    ---@field private fatal_handlers function[] 灾难错误处理函数列表。
    Runtime = {}

    Runtime.ROUTINE_BURST_MODE = 0
    Runtime.ROUTINE_SEQUENCE_MODE = 1
    Runtime.ROUTINE_RANDOM_MODE = 2
    Runtime.routine_mode = Runtime.ROUTINE_BURST_MODE -- 默认采用猝发式例程

    Runtime.routine_mask_flag = false
    Runtime.routine_busy_flag = false
    Runtime.routine_context = {}

    Runtime.expected_sleep_time = 10
    Runtime.actual_sleep_time = 10

    Runtime.routine_mask_flag_stack = {}
    Runtime.last_exception = Exception
    Runtime.fatal_handlers = {}

    ---获取当前程序运行时间，单位为毫秒。
    ---@return integer
    function Runtime:get_running_time()
        return GetRunningTime()
    end

    ---将例程标志位压栈。
    function Runtime:push_routine_mask_flag()
        self.routine_mask_flag_stack[#self.routine_mask_flag_stack + 1] = self.routine_mask_flag
    end

    ---从栈中恢复最近一次的例程标志位。
    function Runtime:pop_routine_mask_flag()
        if #self.routine_mask_flag_stack < 1 then
            return
        end
        self.routine_mask_flag = self.routine_mask_flag_stack[#self.routine_mask_flag_stack]
        self.routine_mask_flag_stack[#self.routine_mask_flag_stack] = nil
    end

    ---启用例程。
    function Runtime:enable_routine()
        Runtime.routine_mask_flag = false
    end

    ---禁用例程。
    function Runtime:disable_routine()
        Runtime.routine_mask_flag = true
    end

    ---判断例程是否处于屏蔽状态。
    ---@return boolean
    function Runtime:is_routine_masked()
        return Runtime.routine_mask_flag
    end

    ---挂起当前执行流，挂起后，可以处理例程事件。除了 `Runtime` 内部方法外，其他地方都应当调用 `Runtime:sleep`，而非直接调用罗技 API 中的 Sleep，这样可以进行例程处理。
    ---@param milliseconds? integer 挂起的时间。
    ---@param precise? boolean 是否需要尽力保证精度。
    function Runtime:sleep(milliseconds, precise)
        milliseconds = milliseconds or 0
        milliseconds = math.floor(milliseconds) -- 防止提供小数时间，若类型非 `number` 会返回 `nil`
        -- 将长时间的休眠拆分为若干短时间休眠，确保 `Runtime` 常常保持对程序的控制权
        while true do
            local expected_sleep_time = 0.5 * self.expected_sleep_time + 0.5 * self.actual_sleep_time
            -- 罗技 API 不支持真正的例程，故而当某个过程主动将自己挂起时（即调用Runtime:sleep)视为自发例程，此时可以处理外部事件
            local before_int = Runtime:get_running_time()
            -- 先执行例程处理
            self:routine()
            -- 例程处理结束后，再校验参数（无论如何都要进行例程处理，即便参数非法）
            if type(milliseconds) ~= "number" or milliseconds < 0 then
                return
            end
            -- 预测下一次休眠会消耗的时间
            local after_int = Runtime:get_running_time()
            local int_time = after_int - before_int
            milliseconds = milliseconds - int_time -- 去除例程处理耗时

            if
                milliseconds > expected_sleep_time -- 大于预计休眠时间
            then
                local start_timepoint = Runtime:get_running_time()
                Sleep(10) -- 按照 10 ms 时间片大小进行休眠
                local end_timepoint = Runtime:get_running_time()
                local real_sleep_time = end_timepoint - start_timepoint
                milliseconds = milliseconds - real_sleep_time -- 减去实际睡眠时间
                -- 更新预测值和实际值
                self.expected_sleep_time, self.actual_sleep_time = expected_sleep_time, real_sleep_time
            elseif
                milliseconds > 0 -- 0 ＜ milliseconds ≤ expected_sleep_time
            then
                if
                    precise -- 需要较高精度，剩余时间采用忙等
                then
                    local begin = Runtime:get_running_time()
                    repeat
                    until Runtime:get_running_time() - begin >= milliseconds -- 忙等以确保精度符合要求
                else
                    Sleep(milliseconds) -- 不考虑精度，按照剩余时间直接休眠
                end
                break
            else -- milliseconds ≤ 0
                break
            end
        end
    end

    Runtime.routines = {}

    ---猝发式例程处理。
    function Runtime:routine_in_burst()
        if
            Runtime.routine_busy_flag -- 当前有正在处理的例程，跳过
        then
            return
        end
        local exception = nil
        -- 例程开始时，例程标志位使能以屏蔽后续例程
        for _, routine in ipairs(self.routines) do
            -- 执行例程处理，若处理过程中出现错误，则先暂存错误，目的是确保 `routine_flag` 正常恢复
            if
                not routine:is_maskable() or not self:is_routine_masked() -- 例程可运行，或该例程不可屏蔽
            then
                self:try_catch_finally(
                    function()
                        self:push_routine_mask_flag()
                        self:disable_routine()
                        self.routine_busy_flag = true
                        routine:handle()
                    end,
                    function(e)
                        exception = e
                    end,
                    function()
                        self.routine_busy_flag = false
                        self:pop_routine_mask_flag()
                        if exception then
                            self:throw(exception) -- 将例程处理过程中引发的错误上抛
                        end
                    end
                )
            end
        end
    end

    Runtime.last_routine_id = 0
    ---顺序式例程处理。
    function Runtime:routine_in_sequence()
        if
            Runtime.routine_busy_flag -- 当前有正在处理的例程，跳过
        then
            return
        end
        if (self.last_routine_id >= #self.routines) then -- 上一次执行的例程是最后一个
            self.last_routine_id = 0
        end
        local id = self.last_routine_id + 1
        local routine = self.routines[id] or Routine -- 如果为空，则用默认的例程模板代替
        local exception = nil
        -- 例程开始时，例程标志位使能以屏蔽后续例程
        -- 执行例程处理，若处理过程中出现错误，则先暂存错误，目的是确保 `routine_flag` 正常恢复
        if
            not routine:is_maskable() or not self:is_routine_masked()
        then
            self:try_catch_finally(
                function()
                    self:push_routine_mask_flag()
                    self:disable_routine()
                    self.routine_busy_flag = true
                    routine:handle()
                end,
                function(e)
                    exception = e
                end,
                function()
                    self.routine_busy_flag = false
                    self:pop_routine_mask_flag()
                    self.last_routine_id = id
                    -- 例程处理完毕，修改最近一次执行的例程 ID
                    if exception then
                        self:throw(self.last_exception) -- 将例程处理过程中引发的错误上抛
                    end
                end
            )
        end
    end

    ---随机式例程处理。
    function Runtime:routine_at_random()
        local int_status
        local int_result --[[@as any]]
        int_result = "ROUTINE_HANDLER_SUCCESS"
        if
            Runtime.routine_busy_flag -- 当前有正在处理的例程，跳过
        then
            return
        end
        local routine = Routine
        if #self.routines > 0 then
            routine = self.routines[math.random(1, #self.routines)]
        end
        local exception = nil
        -- 例程开始时，例程标志位使能以屏蔽后续例程
        -- 执行例程处理，若处理过程中出现错误，则先暂存错误，目的是确保 `routine_flag` 正常恢复
        if
            not routine:is_maskable() or not self:is_routine_masked()
        then
            Runtime:try_catch_finally(
                function()
                    self:push_routine_mask_flag()
                    self:disable_routine()
                    self.routine_busy_flag = true
                    routine:handle()
                end,
                function(e)
                    exception = e
                end,
                function()
                    self.routine_busy_flag = false
                    self:pop_routine_mask_flag()
                    if exception then
                        self:throw(exception) -- 将例程处理过程中引发的错误上抛
                    end
                end
            )
        end
    end

    function Runtime:routine()
        if self.routine_mode == self.ROUTINE_BURST_MODE then
            self:routine_in_burst()
        elseif self.routine_mode == self.ROUTINE_SEQUENCE_MODE then
            self:routine_in_sequence()
        elseif self.routine_mode == self.ROUTINE_RANDOM_MODE then
            self:routine_at_random()
        end
    end

    ---切换采用猝发式例程/顺序式例程。
    ---@param mode integer
    function Runtime:set_routine_mode(mode)
        self.routine_mode = mode
    end

    ---注册例程。
    ---@param routine Routine 例程回调函数或例程处理流程初始化列表
    ---@return integer id
    function Runtime:register_routine(routine)
        local id = #self.routines + 1
        self.routines[id] = routine
        return id
    end

    ---注销例程。
    ---@param id integer 例程标识符
    ---@return boolean
    function Runtime:unregister_interrput(id)
        if self.routines[id] then
            self.routines[id]:kill()
            return true
        end
        return false
    end

    ---注册例程现场，例程发生时保存。
    ---@param context_object Context
    ---@return boolean
    function Runtime:register_context(context_object)
        if type(context_object.save_callback) == "function" and type(context_object.restore_callback) == "function" then
            self.routine_context[#self.routine_context + 1] = context_object
            return true
        end
        return false
    end

    ---注销例程现场。
    ---@param context_object Context
    ---@return boolean
    function Runtime:unregister_context(context_object)
        for index, value in pairs(self.routine_context) do
            if value == context_object then
                table.remove(self.routine_context, index)
                return true
            end
        end
        return false
    end

    ---判断是否在模拟环境中运行。
    ---@return boolean
    function Runtime:emulating()
        return __RunningInEmulator__
    end

    ---判定运行状态，若在 LGHUB 中运行，则返回 true；若在模拟器中运行，则只有在模拟状态下才返回 true。
    ---@return boolean
    function Runtime:runnable()
        return not __RunningInEmulator__ or __IsEmulating__()
    end

    ---抛出一个错误。
    ---@param e Exception 异常对象
    function Runtime:throw(e)
        self.last_exception = e --[[@as Exception]]
        error(e)
    end

    ---尝试执行一段代码，并捕获其中的错误。
    ---@param try fun() 需要执行的代码块
    ---@param catch fun(e: Exception) 错误处理函数
    ---@param finally fun()|nil 最终处理函数
    function Runtime:try_catch_finally(try, catch, finally)
        local exception
        local ok = xpcall(try, function(e)
            if Exception:is_instance(e) then
                exception = e
            elseif type(e) == "table" then
                exception = Exception:new(e)
            else
                exception = Exception:new({
                    name = "__UNKNOWN_ERROR__",
                    message = tostring(e),
                })
            end
            exception:set_traceback(debug.traceback()) -- 记录堆栈
        end)
        if not ok then
            catch(exception)
        end
        if finally then
            finally()
        end
    end

    ---注册灾难错误处理函数。
    ---@param f fun() 处理函数
    ---@return integer index 为处理函数分配的索引号
    function Runtime:register_fatal_handler(f)
            self.fatal_handlers[#self.fatal_handlers + 1] = f
            return #self.fatal_handlers
    end

    ---注销灾难错误处理函数。
    ---@param index integer 处理函数的索引号
    ---@return boolean
    function Runtime:unregister_fatal_handler(index)
        if self.fatal_handlers[index] then
            self.fatal_handlers[index] = function () end -- 占位，避免索引号变动
            return true
        end
        return false
    end

    ---发生灾难错误时的处理函数。
    ---@param e Exception 导致灾难错误的异常对象
    function Runtime:fatal(e)
        for _, f in pairs(self.fatal_handlers) do -- 执行所有注册的灾难错误处理函数
            if type(f) == "function" then
                pcall(f)
            end
        end
        error(("程序发生灾难错误，无法继续运行。灾难错误：%s"):format(tostring(e))) -- 抛出致命错误
    end
end -- __RUNTIME_LUA__
